package org.ndx.jsg.output;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.util.Collection;
import java.util.LinkedList;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.apache.commons.configuration.Configuration;
import org.ndx.jsg.FileInfos;
import org.ndx.jsg.MimeTypes;
import org.ndx.jsg.config.DefaultConfiguration;

/**
 * File copier inspired by the ant task of the same name (http://ant.apache.org/manual/CoreTasks/copy.html). Uses input file location to copy file to output
 * 
 * @author ndx
 * 
 */
public class FileCopier extends OutputProviderAdapter implements OutputProvider {
	private static final Logger logger = Logger.getLogger(FileCopier.class.getName());
	/**
	 * Collection of files to copy, will be copied on {@link #terminate(Configuration)} operation
	 */
	private Collection<FileInfos> filesToCopy = new LinkedList<FileInfos>();
	/**
	 * List of extensions to copy
	 */
	private String[] mimeTypes;
	
	/**
	 * Get inclusion/exclusion pattern. Notice that default inclusion pattern contains all image types
	 */
	@Override
	public void prepare(Configuration config) {
		super.prepare(config);
		mimeTypes = config.getStringArray(DefaultConfiguration.COPY_INCLUDE_MIME);
	}

	/**
	 * Copy file from source to dest, if file extension is in pattern (to
	 * implement latter)
	 */
	@Override
	public void handle(FileInfos infos) {
		if(mimeTypes==null) {
			filesToCopy.add(infos);
		} else {
			for(String mime : mimeTypes) {
				if(mime.equals(infos.getMimeType())) {
					filesToCopy.add(infos);
					return;
				}
			}
		}
	}
	
	@Override
	public void terminate(Configuration config) {
		File outputRoot = new File(config
				.getString(DefaultConfiguration.OUTPUT_PATH));
		logger.info(filesToCopy.size()+" files to direct copy");
		for(FileInfos infos : filesToCopy) {
			copy(infos, outputRoot);
		}
	}

	/**
	 * Copy input file to output folder.
	 * Input file will be put at a location built from outputRoot + {@link File#separator} + {@link FileInfos#getRelativePath()}
	 * @param infos
	 * @param outputRoot
	 */
	public void copy(FileInfos infos, File outputRoot) {
		File output = new File(outputRoot.getAbsolutePath()+File.separator+infos.getRelativePath());
		if(logger.isLoggable(Level.FINER))
			logger.finer("copying file "+infos.getRelativePath()+" to "+output.getAbsolutePath());
		try {
			output.getParentFile().mkdirs();
			FileChannel inChannel = new FileInputStream(infos.getFile())
					.getChannel();
			FileChannel outChannel = new FileOutputStream(output).getChannel();
			try {
				inChannel.transferTo(0, inChannel.size(), outChannel);
			} catch (IOException e) {
				throw e;
			} finally {
				if (inChannel != null)
					inChannel.close();
				if (outChannel != null)
					outChannel.close();
			}
		} catch(Exception e) {
			logger.log(Level.WARNING, "unable to copy from "+infos.getFile().getAbsolutePath()+" to "+output.getAbsolutePath(), e);
		}
	}
}
